//
// XCODE-IU9011 Device Driver for Windows 7
// Copyright (C)2012 Jhlim
//

#pragma warning(disable:4200)  
#pragma warning(disable:4201)  
#pragma warning(disable:4214)  

#include <initguid.h>
#include <wdm.h>
#include "usbdi.h"
#include "usbdlib.h"

#pragma warning(default:4200)
#pragma warning(default:4201)
#pragma warning(default:4214)

#include <wdf.h>
#include <wdfusb.h>

#include "ringBuf.h"
#include "public.h"
#include "prototypes.h"
#include "ioctl.h"

NTSTATUS XIU9011_CanceltHandler(IN WDFUSBDEVICE usbTagetDevice, IN ULONG_PTR p_completeLength)
{
	NTSTATUS ntStatus;
	
	WDF_USB_CONTROL_SETUP_PACKET setup;
	
	WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(
		&setup,
		BmRequestHostToDevice,
		BmRequestToDevice,
		0x01,
		0x00,
		0x00);
	setup.Packet.wLength = 0x0;
	
	ntStatus = WdfUsbTargetDeviceSendControlTransferSynchronously(
					usbTagetDevice,
					NULL,
					NULL,
					&setup,
					NULL,
					(PULONG)p_completeLength);
					
	return ntStatus;
}

NTSTATUS XIU9011_SoftResetHandler(IN WDFUSBDEVICE usbTagetDevice, IN ULONG_PTR p_completeLength)
{
	NTSTATUS ntStatus;
	
	WDF_USB_CONTROL_SETUP_PACKET setup;
	
	WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(
		&setup,
		BmRequestHostToDevice,
		BmRequestToDevice,
		0x02,
		0x00,
		0x00);
	setup.Packet.wLength = 0x0;
	
	ntStatus = WdfUsbTargetDeviceSendControlTransferSynchronously(
					usbTagetDevice,
					NULL,
					NULL,
					&setup,
					NULL,
					(PULONG)p_completeLength);
					
	return ntStatus;
} 

NTSTATUS XIU9011_AbortHandler(IN WDFUSBDEVICE usbTagetDevice, IN ULONG_PTR p_completeLength)
{
	NTSTATUS ntStatus;
	LARGE_INTEGER 			deltaTime;
	   	
	WDF_USB_CONTROL_SETUP_PACKET setup;
	
	WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(
		&setup,
		BmRequestHostToDevice,
		BmRequestToDevice,
		0x03,
		0x00,
		0x00);
	setup.Packet.wLength = 0x0;
	
	ntStatus = WdfUsbTargetDeviceSendControlTransferSynchronously(
					usbTagetDevice,
					NULL,
					NULL,
					&setup,
					NULL,
					(PULONG)p_completeLength);
					
	deltaTime.LowPart = XIU9011_DELAY_VALUE;
    deltaTime.HighPart = -1;
    
    KeDelayExecutionThread(KernelMode, FALSE, &deltaTime);
					
	return ntStatus;
}

NTSTATUS XIU9011_WritePipeHandler(IN WDFUSBPIPE pipe, IN WDFREQUEST request, IN ULONG_PTR p_completeLength)
{
	NTSTATUS	            ntStatus;
    WDFMEMORY               memory;
    WDF_MEMORY_DESCRIPTOR   memDesc;

    ntStatus = WdfRequestRetrieveInputMemory(request, &memory);
	if (!NT_SUCCESS(ntStatus)) {
        KdPrint(("[XIU9011] WritePipeHandler : WdfRequestRetrieveInputMemory Err (0x%x)\n", ntStatus));
        *(ULONG *)p_completeLength = 0;
        goto EXIT;
	}
	
	WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&memDesc, memory,  NULL);
                                  
    ntStatus = WdfUsbTargetPipeWriteSynchronously(pipe, request, NULL, &memDesc, (PULONG)p_completeLength);
	if (!NT_SUCCESS(ntStatus)) {
        KdPrint(("[XIU9011] WritePipeHandler : WdfUsbTargetPipeWriteSynchronously Err (0x%x)\n", ntStatus));
        *(ULONG *)p_completeLength = 0;
        goto EXIT;
	}
    
EXIT:
    return ntStatus;    
}
		   
NTSTATUS XIU9011_ReadCntHandler (IN WDFREQUEST request, IN RING_BUF *p_rb, IN ULONG_PTR p_completeLength)
{
    NTSTATUS    ntStatus = STATUS_SUCCESS;
    INT32       *p_readCntVal;
    size_t      len;
    
    ntStatus = WdfRequestRetrieveOutputBuffer(request, 0, (PVOID)&p_readCntVal, &len);
    if(!NT_SUCCESS(ntStatus)) {
        KdPrint(("[XIU9011] XIU9011_ReadCntHandler: WdfRequestRetrieveOutputBuffer Err \n"));
        return ntStatus;
    }
    
    // Acquire ring_buf lock
    WdfSpinLockAcquire(p_rb->lock);
    
    *p_readCntVal = rb_getAvailableDataSize(p_rb);
    
    // Release ring_buf lock
    WdfSpinLockRelease(p_rb->lock);
    
    *(ULONG *)p_completeLength = len;
    
    return ntStatus;
}

NTSTATUS XIU9011_ReadDataHander (IN WDFREQUEST request, IN RING_BUF *p_rb, IN ULONG_PTR p_completeLength)
{
    UCHAR *p_buf;
    size_t len;
    size_t availCnt;
    LARGE_INTEGER deltaTime;
    ULONG i;
    NTSTATUS ntStatus = STATUS_SUCCESS;
           
    ntStatus = WdfRequestRetrieveOutputBuffer(request, 0, (PVOID)&p_buf, &len);
    if(!NT_SUCCESS(ntStatus)) {
        KdPrint(("[XIU9011] XIU9011_ReadDataHander: WdfRequestRetrieveOutputBuffer Err \n"));
        *(ULONG *)p_completeLength = 0;
        return ntStatus;
    }

    for ( i = 0; i < XIU9011_RETRY_CNT; i++)
	{    
	    // Acquire ring_buf lock
	    WdfSpinLockAcquire(p_rb->lock);
	    
	    availCnt = rb_getAvailableDataSize(p_rb);
	    
	    // Release ring_buf lock
	    WdfSpinLockRelease(p_rb->lock);
	    
	    
	    if(availCnt >= len) {
	    	break;
	    }
	    else {
	    	deltaTime.LowPart = XIU9011_DELAY_VALUE;
	    	deltaTime.HighPart = -1;
	    	KeDelayExecutionThread(KernelMode, FALSE, &deltaTime);
	    }
	}
	
	if( i == XIU9011_RETRY_CNT) {
		KdPrint(("[XIU9011] XIU9011_ReadDataHander: There is no enough data at Ring Buf \n"));
		*(ULONG *)p_completeLength = 0;
		return STATUS_UNSUCCESSFUL;
	}
			
    *(ULONG *)p_completeLength = rb_read(p_rb, p_buf, len);
    return ntStatus;
}
	    